use crate::{
    constant::*,
    model::{Piece, UnblockModel, UnblockState},
};
use log::info;
use tge::{
    context::Context,
    event::{event_check, event_emit, event_register, timer_stage},
    game::{Model, Render},
    render::sprite::{BorderType, Borders, Sprites, Sprite},
    render::style::{Color, Style},
    render::terminal::Term,
};

const COLORS: [Color; 12] = [
    Color::DarkGray,
    Color::Green,
    Color::Yellow,
    Color::Blue,
    Color::Magenta,
    Color::Cyan,
    Color::LightRed,
    Color::LightGreen,
    Color::LightBlue,
    Color::LightYellow,
    Color::LightMagenta,
    Color::LightCyan,
];

#[derive(Clone, Debug)]
pub struct Cell {
    pub x: u8,
    pub y: u8,
    pub kind: u8,
}

const PIECE_CELLS: [&[Cell]; 5] = [
    &[
        Cell {
            x: 0,
            y: 0,
            kind: 14,
        },
        Cell {
            x: 1,
            y: 0,
            kind: 13,
        },
    ],
    &[
        Cell {
            x: 0,
            y: 0,
            kind: 14,
        },
        Cell {
            x: 1,
            y: 0,
            kind: 13,
        },
    ],
    &[
        Cell {
            x: 0,
            y: 0,
            kind: 11,
        },
        Cell {
            x: 0,
            y: 1,
            kind: 7,
        },
    ],
    &[
        Cell {
            x: 0,
            y: 0,
            kind: 14,
        },
        Cell {
            x: 1,
            y: 0,
            kind: 12,
        },
        Cell {
            x: 2,
            y: 0,
            kind: 13,
        },
    ],
    &[
        Cell {
            x: 0,
            y: 0,
            kind: 11,
        },
        Cell {
            x: 0,
            y: 1,
            kind: 3,
        },
        Cell {
            x: 0,
            y: 2,
            kind: 7,
        },
    ],
];

pub struct UnblockRender {
    pub term: Term,
    pub main_scene: Sprites,
    pub boxes: Sprites,
}

impl UnblockRender {
    pub fn new() -> Self {
        let t = Term::new();

        //把17种不同边框的方块存储在boxes中
        //cc0为带修饰角的空白，cc16为全空白
        let mut bs = Sprites::new("boxes");
        for i in 0..17usize {
            let mut ts = Sprite::new(0, 0, CELLSIZEX as u16, CELLSIZEY as u16);
            let cn = format!("assets/city/cc{}.txt", i);
            ts.load_esc(&cn, 0, 0);
            bs.add(ts);
        }

        let mut s = Sprites::new("main");

        let mut tsback = Sprite::new(11, 0, 80, 5);
        let tw = tsback.load_esc("assets/unblock/unblock.txt", 0, 0);
        info!("unblock.txt size ...{:?}", tw);
        s.add_by_tag(tsback, "back");

        let ml = Sprite::new(18, 5, UNBLOCKW as u16, 1u16);
        s.add_by_tag(ml, "UNBLOCK-MSG");

        let mut l = Sprite::new(OFFX, OFFY, (UNBLOCKW + 2) as u16, (UNBLOCKH + 2) as u16);
        l.set_border(
            Borders::ALL,
            BorderType::Rounded,
            Style::default().fg(Color::DarkGray),
        );
        s.add_by_tag(l, "UNBLOCK-BORDER");

        //36个单元块
        for i in 0..WIDTH * HEIGHT {
            s.add_by_tag(
                Sprite::new(0, 0, CELLSIZEX as u16, CELLSIZEY as u16),
                &format!("cc{}", i),
            );
        }

        let mut sl = Sprite::new(
            2,
            (UNBLOCKH + 2 + OFFY as usize) as u16,
            UNBLOCKW as u16,
            1u16,
        );
        sl.content.set_str(
            1,
            0,
            "Press 'n' select new stage. Press 'r' replay this stage.",
            Style::default().fg(COLORS[0]),
        );
        s.add_by_tag(sl, "UNBLOCK-SMSG");

        event_register("Unblock.RedrawGrid", "draw_grid");
        event_register("Unblock.Clear", "clear");

        Self {
            term: t,
            main_scene: s,
            boxes: bs,
        }
    }

    pub fn draw_piece(&mut self, pi: &Piece) {
        let cs = PIECE_CELLS[pi.kind as usize - 1];
        let mut count = 0;
        for c in cs {
            let l = self
                .main_scene
                .get_by_tag(&format!("cc{}", pi.start_cell_id + c.y * WIDTH + c.x));
            l.copy_content(&self.boxes[c.kind as usize]);
            l.set_pos(
                ((pi.x + c.x as f32) * CELLSIZEX as f32) as u16 + 1 + OFFX,
                ((pi.y + c.y as f32) * CELLSIZEY as f32) as u16 + 1 + OFFY,
            );
            //设置颜色
            let col = if pi.kind == 1 { 6 } else { 11 };
            #[cfg(feature = "sdl")]
            l.content.set_style(
                l.content.area,
                Style::default().fg(COLORS[col]).bg(Color::Indexed(1)),
            );
            #[cfg(not(feature = "sdl"))]
            l.content
                .set_style(l.content.area, Style::default().fg(COLORS[col]));
            //设置内容
            if count == 1 && pi.kind == 1 {
                l.content
                    .set_str(4, 2, "🚀", Style::default().fg(COLORS[10]));
            }
            count += 1;
        }
    }

    pub fn clear<G: Model>(&mut self, _context: &mut Context, _model: &mut G) {
        //36个单元块
        for i in 0..WIDTH * HEIGHT {
            let l = self.main_scene.get_by_tag(&format!("cc{}", i));
            l.copy_content(&self.boxes[16]);
        }
    }

    pub fn redraw_grid<G: Model>(&mut self, _context: &mut Context, model: &mut G) {
        let d = model.as_any().downcast_ref::<UnblockModel>().unwrap();
        for p in &d.layout_run.pieces {
            self.draw_piece(p);
        }
        let msg: String;
        let l = self.main_scene.get_by_tag("UNBLOCK-MSG");
        msg = format!(
            "Stage : {}   Moves : {}             ",
            d.map_index, d.layout_run.moves
        );
        l.content.set_str(0, 0, msg, Style::default().fg(COLORS[0]));
    }

    pub fn draw_win_movie<G: Model>(&mut self, context: &mut Context, model: &mut G) {
        if context.state != UnblockState::WinMoving as u8 {
            return;
        }
        let d = model.as_any().downcast_ref::<UnblockModel>().unwrap();
        let l = self.main_scene.get_by_tag(&format!("cc{}", d.main_piece));
        let mut color_idx: usize = 1;
        let frs = timer_stage("Unblock.WinMovie");
        if frs != 0 {
            color_idx = (frs / 3) as usize % COLORS.len();
        }
        let ss = [">>    ", "  >>  ", "    >>"];
        l.content.set_str(
            2,
            2,
            ss[(frs / 3 % 3) as usize],
            Style::default().fg(COLORS[color_idx]),
        );
    }

    pub fn draw_win<G: Model>(&mut self, context: &mut Context, model: &mut G) {
        if context.state != UnblockState::Win as u8 {
            return;
        }
        let d = model.as_any().downcast_ref::<UnblockModel>().unwrap();
        let l = self.main_scene.get_by_tag(&format!("cc{}", d.main_piece));
        l.content
            .set_str(2, 2, "success", Style::default().fg(COLORS[0]));
    }
}

impl Render for UnblockRender {
    fn init(&mut self, context: &mut Context) {
        context.adapter.init(91, 40, 2.0, 1.0, "unblock".to_string());
        self.term.init(context);
    }

    fn handle_event<G: Model>(&mut self, context: &mut Context, data: &mut G, _dt: f32) {
        if event_check("Unblock.RedrawGrid", "draw_grid") {
            self.redraw_grid(context, data);
        }
        if event_check("Unblock.Clear", "clear") {
            self.clear(context, data);
            event_emit("Unblock.RedrawGrid");
        }
    }

    fn handle_timer<G: Model>(&mut self, _context: &mut Context, _model: &mut G, _dt: f32) {}

    fn draw<G: Model>(&mut self, context: &mut Context, data: &mut G, _dt: f32) {
        self.draw_win_movie(context, data);
        self.draw_win(context, data);
        self.term
            .draw(context, |f| {
                self.main_scene.render_all(f);
            })
            .unwrap();
    }
}
